package ru.amse.tsyganov.jumleditor.view.collaboration;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;

import ru.amse.tsyganov.jumleditor.graphicaleditor.Coordinates;
import ru.amse.tsyganov.jumleditor.model.collaboration.Instance;
import ru.amse.tsyganov.jumleditor.model.common.GraphModel;
import ru.amse.tsyganov.jumleditor.properties.BooleanProperty;
import ru.amse.tsyganov.jumleditor.properties.StringProperty;
import ru.amse.tsyganov.jumleditor.validator.Problem;
import ru.amse.tsyganov.jumleditor.validator.Validator;
import ru.amse.tsyganov.jumleditor.view.SelectedItems;
import ru.amse.tsyganov.jumleditor.view.Validity;
import ru.amse.tsyganov.jumleditor.view.ViewVisitor;
import ru.amse.tsyganov.jumleditor.view.common.GraphView;
import ru.amse.tsyganov.jumleditor.view.common.StateView;
import ru.amse.tsyganov.jumleditor.view.preferences.Colors;
import ru.amse.tsyganov.jumleditor.view.preferences.Images;

public class InstanceView<T extends Instance> extends StateView<T> {

	private final static int OBJECT_DEFAULT_WIDTH = 70;
	
	private final static int OBJECT_DEFAULT_HEIGHT = 50;
	
	private static final int HORIZONTAL_MARGIN = 10;
	
	private static final int VERTICAL_MARGIN = 5;
	
	public InstanceView(T model, 
			GraphView<? extends GraphModel> activityGraphView) {
		
		super(model, activityGraphView);
		
		setWidth(OBJECT_DEFAULT_WIDTH);
		setHeight(OBJECT_DEFAULT_HEIGHT);
		
		initProperties();
	}
	
	@Override
	public void accept(ViewVisitor v) {
		v.visitInstanceView(this);
		visitTransitions(v);
	}
	
	public Color getFillColor() {
		return Colors.getGreenColor();
	}

	public String getClassName() {
		return "CollaborationObjectView";
	}

	@Override
	public List<Problem> getInnerProblems() {
		ArrayList<Problem> problems = new ArrayList<Problem>();
		if (getModel().getStateVertex().incomingTransitionsSize() 
				+ getModel().getStateVertex().outgoingTransitionsSize() == 0) {
			
			SelectedItems problemSpace = new SelectedItems();
			problemSpace.selectedStatesAdd(this);
			
			String message = Validator.ERROR +  
				": object is not connected with other objects";
			
			problems.add(new Problem(message, 
					problemSpace, Images.getErrorImage()));
			
			setValidity(Validity.ERROR);
		}
		return problems;
	}
	
	@Override
	public void prepaintEvent(GC gc, Coordinates coordinates) {
		super.prepaintEvent(gc, coordinates);
		
		String text = getText();
		
		Point extent = gc.stringExtent(text);
		
		if (getWidth() < extent.x + 2 * HORIZONTAL_MARGIN - 10) {
			setWidth(extent.x + 2 * HORIZONTAL_MARGIN);
		}
		if (getHeight() < extent.y + 2 * VERTICAL_MARGIN - 10) {
			setHeight(extent.y + 2 * VERTICAL_MARGIN);
		}
	}

	@Override
	public void paintFigure(GC gc, Coordinates coordinates) {
		assert gc != null;
		
		int d = 10;
		
		gc.setBackground(getFillColor());
		gc.setForeground(getValidity().getColor());
		gc.setLineWidth(getModel().isActive() ? 3 : 0);
		
		if (getModel().isMultipleInstances()) {
			gc.fillRectangle(
					coordinates.fromModelXToScreenX(getX() + d), 
					coordinates.fromModelYToScreenY(getY()), 
					getWidth() - d, getHeight() - d);
			
			gc.drawRectangle(
					coordinates.fromModelXToScreenX(getX() + d), 
					coordinates.fromModelYToScreenY(getY()), 
					getWidth() - d, getHeight() - d);
			
			gc.fillRectangle(
					coordinates.fromModelXToScreenX(getX()), 
					coordinates.fromModelYToScreenY(getY() + d), 
					getWidth() - d, getHeight() - d);
			
			gc.drawRectangle(
					coordinates.fromModelXToScreenX(getX()), 
					coordinates.fromModelYToScreenY(getY() + d), 
					getWidth() - d, getHeight() - d);			
		} else {
			gc.fillRectangle(
					coordinates.fromModelXToScreenX(getX()), 
					coordinates.fromModelYToScreenY(getY()), 
					getWidth(), getHeight());
			
			gc.drawRectangle(
					coordinates.fromModelXToScreenX(getX()), 
					coordinates.fromModelYToScreenY(getY()), 
					getWidth(), getHeight());
		}
		gc.setLineWidth(0);
		
		String text = getText();
		
		Point extent = gc.stringExtent(text);
		
		gc.setForeground(Colors.getBlackColor());
		gc.setLineWidth(0);
		if (!getModel().isMultipleInstances()) {
			d = 0;
		}
		gc.drawText(text, 
				coordinates.fromModelXToScreenX(getX() + (getWidth() - d - extent.x) / 2), 
				coordinates.fromModelYToScreenY(getY() + d + (getHeight() - d - extent.y) / 2));
	
		gc.drawLine(coordinates.fromModelXToScreenX(getX() + (getWidth() - d - extent.x) / 2), 
				coordinates.fromModelYToScreenY(getY() + d + (getHeight() - d + extent.y) / 2), 
				coordinates.fromModelXToScreenX(getX() + (getWidth() - d + extent.x) / 2), 
				coordinates.fromModelYToScreenY(getY() + d + (getHeight() - d + extent.y) / 2));
	}
	
	private String getText() {
		String text;
		if (getModel().getRole().length() == 0) {
			text = getModel().getName();
		} else {
			text = getModel().getName() + " / " + getModel().getRole();
		}
		if (getModel().getType().length() != 0) {
			text += " : " + getModel().getType();
		}
		return text;
	}
	
	private void initProperties() {
		super.getProperties().addProperty(new StringProperty("Role") {

			@Override
			public String getPropertyValue() {
				return getModel().getRole();
			}

			@Override
			public void setPropertyValue(String newValue) {
				getModel().setRole(newValue);
			}
			
		});
		super.getProperties().addProperty(new StringProperty("Type") {

			@Override
			public String getPropertyValue() {
				return getModel().getType();
			}

			@Override
			public void setPropertyValue(String newValue) {
				getModel().setType(newValue);
			}
			
		});
		super.getProperties().addProperty(new BooleanProperty("Active") {

			@Override
			public Boolean getPropertyValue() {
				return getModel().isActive();
			}

			@Override
			public void setPropertyValue(Boolean newValue) {
				getModel().setActive(newValue);
			}

		});
		super.getProperties().addProperty(new BooleanProperty("Multiple instances") {

			@Override
			public Boolean getPropertyValue() {
				return getModel().isMultipleInstances();
			}

			@Override
			public void setPropertyValue(Boolean newValue) {
				getModel().setMultipleInstances(newValue);
			}

		});
	}
	
	@Override
	public StringProperty getMainProperty() {
		return null;
	}
}
